home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / amiga / asrc29k.lha / chatnode.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-08  |  23.2 KB  |  905 lines

  1. /* chatnode server - based on conversd written by DK5SG
  2.  * ported to WNOS by DB3FL - 9109xx/9110xx
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <string.h>
  7. #include <time.h>
  8. #include <ctype.h>
  9. #include "global.h"
  10. #include "config.h"
  11. #ifdef CHATNODE
  12. #ifdef MAILBOX
  13. #include "mailbox.h"
  14. #include "netuser.h"
  15. #endif
  16. #include "timer.h"
  17. #include "cmdparse.h"
  18. #include "socket.h"
  19. #include "session.h"
  20. #include "files.h"
  21. #include "commands.h"
  22.  
  23. static char *cxxtime __ARGS((char *line));
  24. extern char *ptime __ARGS((long *t));
  25.  
  26. static int free_connection __ARGS((register struct convection *cp));
  27. static int free_closed_connections __ARGS((int argc,char *argv[],void *p));
  28. static int update_permlinks __ARGS((char  *name,struct convection *cp));
  29. static struct convection *alloc_connection __ARGS((int  fd));
  30. static int clear_locks __ARGS((int argc,char *argv[],void *p));
  31. static int send_user_change_msg __ARGS((char  *name,char *host,int  oldchannel,int newchannel));
  32. static char *formatline __ARGS((char *prefix,char *text));
  33. static int send_msg_to_user __ARGS((char *fromname,char *toname,char *text));
  34. static int send_msg_to_channel __ARGS((char *fromname,int channel,char *text));
  35. static char *timestring __ARGS((long gmt));
  36. static int send_invite_msg __ARGS((char *fromname,char *toname,int channel));
  37. static int bye_command __ARGS((struct convection *cp));
  38. static int channel_command __ARGS((struct convection *cp));
  39. static int help_command __ARGS((struct convection *cp));
  40. static int invite_command __ARGS((struct convection *cp));
  41. static int links_command __ARGS((struct convection *cp));
  42. static int msg_command __ARGS((struct convection *cp));
  43. static int name_command __ARGS((struct convection *cp));
  44. static int who_command __ARGS((struct convection *cp));
  45. static int h_cmsg_command __ARGS((struct convection *cp));
  46. static int h_host_command __ARGS((struct convection *cp));
  47. static int h_invi_command __ARGS((struct convection *cp));
  48. static int h_user_command __ARGS((struct convection *cp));
  49. static int h_umsg_command __ARGS((struct convection *cp));
  50.  
  51. static void conv_incom __ARGS((int s,void *t,void *p));
  52. static char *getarg __ARGS((char *line, int all));
  53.  
  54. int Sconv = -1;
  55. char *myhostname = NULLCHAR;
  56.  
  57. char cnumber[] = "%s *** Channel numbers must be in the range 0..%d.\n";
  58.  
  59. #define MAXCHANNEL    32767
  60. #define MAX_WAITTIME    (60*60*3)
  61.  
  62. struct convection {
  63.   int  type;                    /* Connection type */
  64. #define CT_UNKNOWN      0
  65. #define CT_USER         1
  66. #define CT_HOST         2
  67. #define CT_CLOSED       3
  68.   char  name[10];        /* Name of user or host */
  69.   char  host[10];        /* Name of host where user is logged on */
  70.   struct convection *via;       /* Pointer to neighbor host */
  71.   int  channel;                 /* Channel number */
  72.   int32 time;                   /* Connect time */
  73.   int  locked;                  /* Set if mesg already sent */
  74.   int  fd;            /* Socket descriptor */
  75.   int  fmask;                   /* Socket mask */
  76.   char  ibuf[LINELEN];          /* Input buffer */
  77.   int  received;                /* Number of bytes received */
  78.   int  xmitted;                 /* Number of bytes transmitted */
  79.   struct convection *next;      /* Linked list pointer */
  80. };
  81.  
  82. #define CM_UNKNOWN   (1 << CT_UNKNOWN)
  83. #define CM_USER      (1 << CT_USER)
  84. #define CM_HOST      (1 << CT_HOST)
  85. #define CM_CLOSED    (1 << CT_CLOSED)
  86.  
  87. #define NULLCONNECTION  ((struct convection *) 0)
  88.  
  89. static struct convection *convections;
  90.  
  91. struct permlink {
  92.   char *name;                  /* Name of host */
  93.   char *link_info;                /* Name of socket to connect to */
  94.   char *command;         /* Optional connect command */
  95.   struct convection *convection;/* Pointer to associated connection */
  96.   int32 statetime;              /* Time of last (dis)connect */
  97.   int  tries;                   /* Number of connect tries */
  98.   int32 waittime;               /* Time between connect tries */
  99.   int32 retrytime;              /* Time of next connect try */
  100.   int fd;            /* socket descriptor */
  101.   struct permlink *next;        /* Linked list pointer */
  102. };
  103. #define NULLPERMLINK  ((struct permlink *) 0)
  104.  
  105. static struct permlink *permlinks;
  106.  
  107. /* Stop chatnode server */
  108. int conv0(argc,argv,p)
  109. int argc;
  110. char *argv[];
  111. void *p;
  112. {
  113.     close_s(Sconv);
  114.     Sconv = -1;
  115.     return 0;
  116. }
  117.  
  118. /* Start up chatnode server */
  119. int conv1(argc,argv,p)
  120. int argc;
  121. char *argv[];
  122. void *p;
  123. {
  124.     struct sockaddr_in lsocket;
  125.     int s;
  126.  
  127.     if(Sconv != -1){
  128.         return 0;
  129.     }
  130.     psignal(Curproc,0);         /* Don't keep the parser waiting */
  131.     chname(Curproc,"Chatnode");
  132.  
  133.     lsocket.sin_family = AF_INET;
  134.     lsocket.sin_addr.s_addr = INADDR_ANY;
  135.     lsocket.sin_port = (argc < 2) ? IPPORT_CHATNODE : atoi(argv[1]);
  136.  
  137.     Sconv = socket(AF_INET,SOCK_STREAM,0);
  138.     bind(Sconv,(char *)&lsocket,sizeof(lsocket));
  139.     listen(Sconv,1);
  140.     myhostname = strdup(Hostname);
  141.     for(;;){
  142.         if((s = accept(Sconv,NULLCHAR,(int *)NULL)) == -1)
  143.             break;            /* Service is shutting down */
  144.  
  145.         if(availmem() < Memthresh){
  146.             shutdown(s,1);
  147.         } else {
  148.             /* Spawn a server */
  149.             newproc("chatnode",2048,conv_incom,s,0,NULL);
  150.         }
  151.     }
  152.  
  153.     return 0;
  154. }
  155.  
  156. static char *getarg(line, all)
  157. char  *line;
  158. int  all;
  159. {
  160.   char  *arg;
  161.   int  c;
  162.   static char  *p;
  163.  
  164.   if (line) p = line;
  165.   while (isspace(uchar(*p))) p++;
  166.   if (all) return p;
  167.   arg = p;
  168.   while (*p && !isspace(uchar(*p))) {
  169.     c = tolower(uchar(*p));
  170.     *p++ = c;
  171.   }
  172.   if (*p) *p++ = '\0';
  173.   return arg;
  174. }
  175.  
  176. static char *cxxtime(line)
  177. char *line;
  178. {
  179.      extern char *Months[];
  180.      static char buf[12];
  181.      char *cp;
  182.      int i, day;
  183.      cp = line;
  184.      while(isspace(*cp))    /* skip initial blanks */
  185.       ++cp;
  186.      if(*cp == '\0')
  187.       return NULLCHAR;
  188.      if(strlen(cp) < 22)
  189.       return NULLCHAR;
  190.      cp += 5;
  191.      day = atoi(cp);
  192.      if(*(++cp) != ' ')
  193.       ++cp;
  194.      ++cp;
  195.      for(i=0; i < 12; ++i)
  196.       if(strnicmp(Months[i],cp,3) == 0)
  197.            break;
  198.      if(i == 12)
  199.       return NULLCHAR;
  200.      sprintf(buf,"%2d-%3s-%2d %02d:%02d",
  201.              day, Months[i], atoi(cp + 4), atoi(cp + 7), atoi(cp + 10));
  202.      return buf;
  203. }
  204.  
  205. static int free_connection(cp)
  206. register struct convection *cp;
  207. {
  208.   register struct permlink *p;
  209.  
  210.   for (p = permlinks; p; p = p->next)
  211.     if (p->convection == cp) p->convection = NULLCONNECTION;
  212.   if (cp->fmask) close_s(cp->fd);
  213.   free((char *) cp);
  214.   return 0;
  215. }
  216.  
  217. static int free_closed_connections(argc,argv,pp)
  218. int argc;
  219. char *argv[];
  220. void *pp;
  221. {
  222.   register struct convection *cp, *p;
  223.  
  224.   for (p = NULLCONNECTION, cp = convections; cp; )
  225.     if (cp->type == CT_CLOSED ||
  226.      cp->type == CT_UNKNOWN && cp->time + 300 < Clock) {
  227.       if (p) {
  228.         p->next = cp->next;
  229.         free_connection(cp);
  230.         cp = p->next;
  231.       } else {
  232.         convections = cp->next;
  233.         free_connection(cp);
  234.         cp = convections;
  235.       }
  236.     } else {
  237.       p = cp;
  238.       cp = cp->next;
  239.     }
  240.     return 0;
  241. }
  242.  
  243. static int update_permlinks(name, cp)
  244. char  *name;
  245. struct convection *cp;
  246. {
  247.   register struct permlink *p;
  248.  
  249.   for (p = permlinks; p; p = p->next)
  250.     if (!strcmp(p->name, name)) {
  251.       p->convection = cp;
  252.       p->statetime = Clock;
  253.       p->tries = 0;
  254.       p->waittime = 60;
  255.       p->retrytime = Clock + p->waittime;
  256.     }
  257.   return 0;
  258. }
  259.  
  260. static struct convection *alloc_connection(fd)
  261. int  fd;
  262. {
  263.   register struct convection *cp;
  264.  
  265.   cp = (struct convection *)callocw(1, sizeof(struct convection ));
  266.   cp->fd = cp->fmask = fd;
  267.   cp->time = Clock;
  268.   cp->next = convections;
  269.   convections = cp;
  270.   return cp;
  271. }
  272.  
  273. static int clear_locks(argc,argv,pp)
  274. int argc;
  275. char *argv[];
  276. void *pp;
  277. {
  278.   register struct convection *p;
  279.  
  280.   for (p = convections; p; p = p->next) p->locked = 0;
  281.   return 0;
  282. }
  283.  
  284. static int send_user_change_msg(name, host, oldchannel, newchannel)
  285. char  *name, *host;
  286. int  oldchannel, newchannel;
  287. {
  288.   time_t cxtime;
  289.   register struct convection *p;
  290.  
  291.   time(&cxtime);
  292.   for (p = convections; p; p = p->next) {
  293.     if (p->type == CT_USER && !p->via && !p->locked) {
  294.       if (p->channel == oldchannel) {
  295.         if (newchannel >= 0)
  296.           p->xmitted += usprintf(p->fd, "%s *** %s switched to channel %d.\n",  cxxtime(ptime(&cxtime)),name, newchannel);
  297.         else
  298.           p->xmitted += usprintf(p->fd, "%s *** %s signed off.\n", cxxtime(ptime(&cxtime)), name);
  299.         p->locked = 1;
  300.       }
  301.       if (p->channel == newchannel) {
  302.         p->xmitted += usprintf(p->fd, "%s *** %s signed on.\n", cxxtime(ptime(&cxtime)), name);
  303.         p->locked = 1;
  304.       }
  305.     }
  306.     if (p->type == CT_HOST && !p->locked) {
  307.       p->xmitted += usprintf(p->fd,
  308.         "/\377\200USER %s %s %d %d %d\n",
  309.         name, host, 0, oldchannel, newchannel);
  310.       p->locked = 1;
  311.     }
  312.   }
  313.   return 0;
  314. }
  315.  
  316. static char *formatline(prefix, text)
  317. char  *prefix, *text;
  318. {
  319.  
  320. #define PREFIXLEN    12
  321. #define CLINELEN    70
  322.  
  323.   register char  *f, *t, *x;
  324.   register int  l, lw;
  325.  
  326.   static char  buf[2048];
  327.  
  328.   for (f = prefix, t = buf; *f; *t++ = *f++) ;
  329.   l = (int)(t - buf);
  330.   f = text;
  331.  
  332.   for (; ; ) {
  333.     while (isspace(uchar(*f))) f++;
  334.     if (!*f) {
  335.       *t++ = '\n';
  336.       *t = '\0';
  337.       return buf;
  338.     }
  339.     for (x = f; *x && !isspace(uchar(*x)); x++) ;
  340.     lw = (int)(x - f);
  341.     if (l > PREFIXLEN && l + 1 + lw > CLINELEN) {
  342.       *t++ = '\n';
  343.       l = 0;
  344.     }
  345.     do {
  346.       *t++ = ' ';
  347.       l++;
  348.     } while (l < PREFIXLEN);
  349.     while (lw--) {
  350.       *t++ = *f++;
  351.       l++;
  352.     }
  353.   }
  354.   return 0;
  355. }
  356.  
  357. static int send_msg_to_user(fromname, toname, text)
  358. char  *fromname, *toname, *text;
  359. {
  360.   register struct convection *p;
  361.   char buffer[20];
  362.  
  363.   for (p = convections; p; p = p->next) {
  364.     if (p->type == CT_USER && !strcmp(p->name, toname))
  365.       if (p->via) {
  366.         if (!p->via->locked) {
  367.           p->via->xmitted += usprintf(p->via->fd,
  368.             "/\377\200UMSG %s %s %s", fromname, toname, text);
  369.           p->via->locked = 1;
  370.         }
  371.       } else {
  372.         if (!p->locked) {
  373.           if (strcmp(fromname, "chatnode")) {
  374.             sprintf(buffer, "<*%s*>:", fromname);
  375.             p->xmitted += usprintf(p->fd,"%s ",
  376.                         formatline(buffer, text));
  377.           } else {
  378.             p->xmitted += usprintf(p->fd,"%s\n", text);
  379.           }
  380.               p->locked = 1;
  381.             }
  382.          }
  383.   }
  384.   return 0;
  385. }
  386.  
  387. static int send_msg_to_channel(fromname, channel, text)
  388. char  *fromname;
  389. int  channel;
  390. char  *text;
  391. {
  392.   register struct convection *p;
  393.   char  buffer[20];
  394.  
  395.   for (p = convections; p; p = p->next) {
  396.     if (p->type == CT_USER && p->channel == channel)
  397.       if (p->via) {
  398.         if (!p->via->locked) {
  399.           p->via->xmitted += usprintf(p->via->fd,
  400.             "/\377\200CMSG %s %d %s\n", fromname, channel, text);
  401.           p->via->locked = 1;
  402.         }
  403.       } else {
  404.         if (!p->locked) {
  405.           sprintf(buffer, "<%s>:", fromname);
  406.           p->xmitted += usprintf(p->fd,"%s", 
  407.                     formatline(buffer, text));
  408.           p->locked = 1;
  409.       }
  410.     }
  411.   }
  412.   return 0;
  413. }
  414.  
  415. static int send_invite_msg(fromname, toname, channel)
  416. char  *fromname, *toname;
  417. int  channel;
  418. {
  419.   time_t cxtime;
  420.   char invitetext[] = "\n\007\007%s *** From %s - Please join CHATNODE channel %d.\n\007\007\n";
  421.   char responsetext[] = "%s *** Invitation sent to %s";
  422.   char cnvd[] = "chatnode";
  423.  
  424.   char buffer[LINELEN];
  425.   struct convection *p;
  426. #ifdef MAILBOX
  427.   int i;
  428.   struct mbx *m;
  429. #endif
  430.  
  431.   time(&cxtime);
  432.   for (p = convections; p; p = p->next) {
  433. #ifdef MAILBOX
  434.     for (i = 0; i < NUMMBX; i++){
  435.       if((m = Mbox[i]) != NULLMBX){
  436.         if(m->state == MBX_CMD && !strcmp(m->name,toname)) {
  437.                   p->xmitted += usprintf(m->user, invitetext, cxxtime(ptime(&cxtime)), fromname, channel);
  438.           usflush(m->user);
  439.           clear_locks(NULL,NULLCHAR,NULL);
  440.           sprintf(buffer, responsetext, cxxtime(ptime(&cxtime)),toname);
  441.           send_msg_to_user(cnvd, fromname, buffer);
  442.           return 0;
  443.         }
  444.       }
  445.     }
  446. #endif
  447.     if (p->type == CT_USER && !strcmp(p->name, toname)) {
  448.       if (p->channel == channel) {
  449.         clear_locks(NULL,NULLCHAR,NULL);
  450.         sprintf(buffer, "%s *** User %s is already on this channel.", cxxtime(ptime(&cxtime)),toname);
  451.         send_msg_to_user(cnvd, fromname, buffer);
  452.         return 0;
  453.       }
  454.       if (!p->via && !p->locked) {
  455.                 time(&cxtime);
  456.         p->xmitted += usprintf(p->fd, invitetext, cxxtime(ptime(&cxtime)), fromname, channel);
  457.         clear_locks(NULL,NULLCHAR,NULL);
  458.         sprintf(buffer, responsetext, cxxtime(ptime(&cxtime)), toname);
  459.         send_msg_to_user(cnvd, fromname, buffer);
  460.         return 0;
  461.       }
  462.       if (p->via && !p->via->locked) {
  463.         p->via->xmitted += usprintf(p->via->fd,
  464.           "/\377\200INVI %s %s %d\n", fromname, toname, channel);
  465.         return 0;
  466.       }
  467.     }
  468.   }
  469.   for (p = convections; p; p = p->next) {
  470.     if (p->type == CT_HOST && !p->locked) {
  471.       p->xmitted += usprintf(p->fd,
  472.         "/\377\200INVI %s %s %d\n", fromname, toname, channel);
  473.     }
  474.   }
  475.   return 0;
  476. }
  477.  
  478. static int bye_command(cp)
  479. struct convection *cp;
  480. {
  481.   register struct convection *p;
  482.  
  483.   switch (cp->type) {
  484.   case CT_UNKNOWN:
  485.     cp->type = CT_CLOSED;
  486.     break;
  487.   case CT_USER:
  488.     cp->type = CT_CLOSED;
  489.     clear_locks(NULL,NULLCHAR,NULL);
  490.     send_user_change_msg(cp->name, cp->host, cp->channel, -1);
  491.     break;
  492.   case CT_HOST:
  493.     cp->type = CT_CLOSED;
  494.     update_permlinks(cp->name, NULLCONNECTION);
  495.     for (p = convections; p; p = p->next)
  496.       if (p->via == cp) {
  497.         p->type = CT_CLOSED;
  498.         clear_locks(NULL,NULLCHAR,NULL);
  499.         send_user_change_msg(p->name, p->host, p->channel, -1);
  500.       }
  501.     break;
  502.   case CT_CLOSED:
  503.     break;
  504.   }
  505.   return 0;
  506. }
  507.  
  508. static int channel_command(cp)
  509. struct convection *cp;
  510. {
  511.   time_t cxtime;
  512.   char  s[7];
  513.   int  newchannel;
  514.  
  515.   time(&cxtime);
  516.   s[0] = '\0';
  517.   sscanf(cp->ibuf,"%*s %6s",s);
  518.   if (s[0] == '\0') {
  519.     cp->xmitted += usprintf(cp->fd,"%s *** You are on channel %d.\n", cxxtime(ptime(&cxtime)),cp->channel);
  520.     return 0;
  521.   }
  522.   newchannel = atoi(s);
  523.   if (newchannel < 0 || newchannel > MAXCHANNEL) {
  524.     cp->xmitted += usprintf(cp->fd,cnumber, cxxtime(ptime(&cxtime)),MAXCHANNEL);
  525.     return 0;
  526.   }
  527.   if (newchannel == cp->channel) {
  528.     cp->xmitted += usprintf(cp->fd,
  529.       "%s *** Already on channel %d.\n", cxxtime(ptime(&cxtime)), cp->channel);
  530.     return 0;
  531.   }
  532.   send_user_change_msg(cp->name, cp->host, cp->channel, newchannel);
  533.   cp->channel = newchannel;
  534.   cp->xmitted += usprintf(cp->fd, "%s *** Now on channel %d.\n", cxxtime(ptime(&cxtime)), cp->channel);
  535.   return 0;
  536. }
  537.  
  538. static int help_command(cp)
  539. struct convection *cp;
  540. {
  541.   cp->xmitted += usprintf(cp->fd, "Commands may be abbreviated. Commands are:\n");
  542.   cp->xmitted += usprintf(cp->fd, "/?                        Print help information\n");
  543.   cp->xmitted += usprintf(cp->fd, "/bye                      Terminate the chatnode session\n");
  544.   cp->xmitted += usprintf(cp->fd, "/channel <n>              Switch to channel <n>\n");
  545.   cp->xmitted += usprintf(cp->fd, "/exit                     Terminate the chatnode session\n");
  546.   cp->xmitted += usprintf(cp->fd, "/help                     Print help information\n");
  547.   cp->xmitted += usprintf(cp->fd, "/invite <user>            Invite <user> to join your channel\n");
  548.   cp->xmitted += usprintf(cp->fd, "/msg <user> <text...>     Send a private message to <user>\n");
  549.   cp->xmitted += usprintf(cp->fd, "/quit                     Terminate the chatnode session\n");
  550.   cp->xmitted += usprintf(cp->fd, "/who [quick] [long]       List all users and their channel numbers\n");
  551.   cp->xmitted += usprintf(cp->fd, "/write <user> <text...>   Send a private message to <user>\n***\n");
  552.   return 0;
  553. }
  554.  
  555. static int invite_command(cp)
  556. struct convection *cp;
  557. {
  558.   char toname[10];
  559.  
  560.   toname[0] = '\0';
  561.   sscanf(cp->ibuf,"%*s %8s",toname);
  562.   if (toname[0] != '\0')
  563.     send_invite_msg(cp->name, toname, cp->channel);
  564.   return 0;
  565. }
  566.  
  567. static int msg_command(cp)
  568. struct convection *cp;
  569. {
  570.   time_t cxtime;
  571.   char dummy[LINELEN], toname[10], *text;
  572.   register struct convection *p;
  573.  
  574.   time(&cxtime);
  575.   toname[0] = '\0';
  576.   sscanf(cp->ibuf,"%s %8s",dummy,toname);
  577.   text = &cp->ibuf[0];
  578.   text += strlen(dummy) + strlen(toname) + 2;
  579.  
  580.   if (!*text) return 0;
  581.   for (p = convections; p; p = p->next)
  582.     if (p->type == CT_USER && !strcmp(p->name, toname))
  583.       break;
  584.   if (!p)
  585.     cp->xmitted += usprintf(cp->fd, "%s *** No such user: %s.\n", cxxtime(ptime(&cxtime)), toname);
  586.   else
  587.     send_msg_to_user(cp->name, toname, text);
  588.   return 0;
  589. }
  590.  
  591. static int name_command(cp)
  592. struct convection *cp;
  593. {
  594.   time_t cxtime;
  595.   int  newchannel;
  596.   char dummy[7];
  597.  
  598.   time(&cxtime);
  599.   cp->name[0] = '\0';
  600.   dummy[0] = '\0';
  601.   sscanf(cp->ibuf,"%*s %8s %6s",cp->name,dummy);
  602.   newchannel = atoi(dummy);
  603.   if (cp->name[0] == '\0') return 0;
  604.   strlwr(cp->name);
  605.   strncpy(cp->host,myhostname,9);
  606.   cp->type = CT_USER;
  607.   cp->xmitted += usprintf(cp->fd,
  608.     "%s *** Host: %s  %s\nType /help for Help.\n",
  609.         cxxtime(ptime(&cxtime)), myhostname, Aversion);
  610.   if (newchannel < 0 || newchannel > MAXCHANNEL) {
  611.     cp->xmitted += usprintf(cp->fd,cnumber, cxxtime(ptime(&cxtime)),MAXCHANNEL);
  612.   } else
  613.     cp->channel = newchannel;
  614.   send_user_change_msg(cp->name, cp->host, -1, cp->channel);
  615.   return 0;
  616. }
  617.  
  618. static int who_command(cp)
  619. struct convection *cp;
  620. {
  621.   char buffer[LINELEN];
  622.   int channel, full = 0, quick = 0;
  623.   struct convection *p;
  624. #ifdef MAILBOX
  625.   int i;
  626.   struct mbx *m;
  627. #endif
  628.  
  629.   buffer[0] = '\0';
  630.   sscanf(cp->ibuf,"%*s %2s",buffer);
  631.   switch(tolower(buffer[0])) {
  632.   case 'l':
  633.     full = 1;
  634.     break;
  635.   case 'q':
  636.     quick = 1;
  637.     break;
  638.   }
  639.  
  640.   if (quick) {
  641.     cp->xmitted += usprintf(cp->fd, "Channel Users\n");
  642.     clear_locks(NULL,NULLCHAR,NULL);
  643.     do {
  644.       channel = -1;
  645.       for (p = convections; p; p = p->next) {
  646.         if (p->type == CT_USER && !p->locked && (channel < 0 || channel == p->channel)) {
  647.           if (channel < 0) {
  648.             channel = p->channel;
  649.             sprintf(buffer, "%7d", channel);
  650.           }
  651.           strcat(buffer, " ");
  652.           strcat(buffer, p->name);
  653.           p->locked = 1;
  654.         }
  655.       }
  656.       if (channel >= 0) {
  657.         cp->xmitted += usprintf(cp->fd, "%s\n",buffer);
  658.       }
  659.     } while (channel >= 0);
  660.   } else {
  661.     cp->xmitted += usprintf(cp->fd,
  662.       "User     Host     Via      Channel    Duration %s\n",
  663.       full ? " HQueue Receivd Xmitted" : "");
  664.     for (p = convections; p; p = p->next) {
  665.       if (p->type == CT_USER) {
  666.         cp->xmitted += usprintf(cp->fd,
  667.           full ?
  668.           "%-8.8s %-8.8s %-8.8s %7d %12s %5d %7d %7d\n" :
  669.           "%-8.8s %-8.8s %-8.8s %7d %12s\n",
  670.           p->name,
  671.           p->host,
  672.           p->via ? p->via->name : "",
  673.           p->channel,
  674.           tformat(Clock - p->time),
  675.           0,            /* always 0 cuz NOS handles the tx-queue */
  676.           p->received,
  677.           p->xmitted);
  678.       }
  679.     }
  680.   }
  681. #ifdef MAILBOX
  682.   for (i = 0; i < NUMMBX; i++) {
  683.     if((m = Mbox[i]) != NULLMBX) {
  684.       if(m->state == MBX_CMD) {
  685.         if(quick)
  686.           cp->xmitted += usprintf(cp->fd," LocBBS %s\n",m->name);
  687.         else
  688.           cp->xmitted += usprintf(cp->fd,"%-8s LocBBS@%s\n",m->name,Hostname);
  689.       }
  690.     }
  691.   }
  692. #endif
  693.   cp->xmitted += usprintf(cp->fd, "***\n");
  694.   return 0;
  695. }
  696.  
  697. static int h_cmsg_command(cp)
  698. struct convection *cp;
  699. {
  700.   char name[LINELEN], dummy[40], *text;
  701.   int  channel;
  702.  
  703.   sscanf(cp->ibuf,"%s %s %d",dummy,name,&channel);
  704.   text = &cp->ibuf[0];
  705.   text += strlen(dummy) + strlen(name) + 2;
  706.   while(isspace(*text) == NULL)
  707.     text++;
  708.   text++;
  709.   if(isprint(*text) != 0)
  710.     send_msg_to_channel(name, channel, text);
  711.   return 0;
  712. }
  713.  
  714. static int h_host_command(cp)
  715. struct convection *cp;
  716. {
  717.   char name[10];
  718.   register struct convection *p;
  719.   register struct permlink *pp;
  720.  
  721.   name[0] = '\0';
  722.   sscanf(cp->ibuf,"%*s %8s",name);
  723.   if (name[0] == '\0') return 0;
  724.   for (p = convections; p; p = p->next)
  725.     if (!strcmp(p->name, name)) bye_command(p);
  726.   for (pp = permlinks; pp; pp = pp->next)
  727.     if (!strcmp(pp->name, name) && pp->convection && pp->convection != cp)
  728.       bye_command((strcmp(myhostname, name) < 0) ? pp->convection : cp);
  729.   if (cp->type != CT_UNKNOWN) return 0;
  730.   cp->type = CT_HOST;
  731.   strcpy(cp->name,name);        /* already allocated */
  732.   update_permlinks(name, cp);
  733.   cp->xmitted += usprintf(cp->fd, "/\377\200HOST %s\n", myhostname);
  734.   for (p = convections; p; p = p->next)
  735.     if (p->type == CT_USER) {
  736.       cp->xmitted += usprintf(cp->fd,
  737.         "/\377\200USER %s %s %d %d %d\n", p->name, p->host, 0, -1, p->channel);
  738.     }
  739.   return 0;
  740. }
  741.  
  742. static int h_invi_command(cp)
  743. struct convection *cp;
  744. {
  745.   char fromname[10], toname[10];
  746.   int  channel;
  747.  
  748.   sscanf(cp->ibuf,"%*s %8s %8s %d",fromname,toname,&channel);
  749.   send_invite_msg(fromname, toname, channel);
  750.   return 0;
  751. }
  752.  
  753. static int h_umsg_command(cp)
  754. struct convection *cp;
  755. {
  756.   char dummy[LINELEN], fromname[10], toname[10], *text;
  757.  
  758.   sscanf(cp->ibuf,"%s %8s %8s",dummy,fromname,toname);
  759.   text = &cp->ibuf[0];
  760.   text += strlen(dummy) + strlen(fromname) + strlen(toname) + 3;
  761.   if (*text)
  762.     send_msg_to_user(fromname, toname, text);
  763.   return 0;
  764. }
  765.  
  766. static int h_user_command(cp)
  767. struct convection *cp;
  768. {
  769.   char host[10], name[10];
  770.   int  newchannel, oldchannel;
  771.   register struct convection *p;
  772.  
  773.   sscanf(cp->ibuf,"%*s %8s %8s %*s %d %d",name,host,&oldchannel,&newchannel);
  774.  
  775.   for (p = convections; p; p = p->next)
  776.     if (p->type == CT_USER       &&
  777.     p->channel == oldchannel &&
  778.     p->via == cp             &&
  779.     !strcmp(p->name, name)   &&
  780.     !strcmp(p->host, host))  break;
  781.   if (!p) {
  782.     p = (struct convection *)callocw(1, sizeof(struct convection ));
  783.     p->type = CT_USER;
  784.     strncpy(p->name,name,9);
  785.     strncpy(p->host,host,9);
  786.     p->via = cp;
  787.     p->channel = oldchannel;
  788.     p->time = Clock;
  789.     p->next = convections;
  790.     convections = p;
  791.   }
  792.   if ((p->channel = newchannel) < 0) p->type = CT_CLOSED;
  793.   send_user_change_msg(name, host, oldchannel, newchannel);
  794.   return 0;
  795. }
  796.  
  797. /* Incoming chatnode session */
  798. static void conv_incom(s,t,p)
  799. int s;
  800. void *t;
  801. void *p;
  802. {
  803.   time_t cxtime;
  804.   char arg[LINELEN];
  805.   int arglen, size;
  806.   struct convection *cp;
  807.   struct permlink *pl;
  808.   char *ccp, *cccp;
  809.  
  810. #ifdef MAILBOX
  811.   int len;
  812.   char fsocket[MAXSOCKSIZE];
  813. #endif
  814.  
  815.   struct cmdtable {
  816.     char  *name;
  817.     int (*fnc) __ARGS((struct convection *cp));
  818.     int  states;
  819.   } cmdtable[] = {
  820.     "?",          help_command,       CM_USER,
  821.     "bye",        bye_command,        CM_USER,
  822.     "channel",    channel_command,    CM_USER,
  823.     "exit",       bye_command,        CM_USER,
  824.     "help",       help_command,       CM_USER,
  825.     "invite",     invite_command,     CM_USER,
  826.     "msg",        msg_command,        CM_USER,
  827.     "name",       name_command,       CM_UNKNOWN,
  828.     "quit",       bye_command,        CM_USER,
  829.     "who",        who_command,        CM_USER,
  830.     "write",      msg_command,        CM_USER,
  831.  
  832.     "\377\200cmsg", h_cmsg_command,   CM_HOST,
  833.     "\377\200host", h_host_command,   CM_UNKNOWN,
  834.     "\377\200invi", h_invi_command,   CM_HOST,
  835.     "\377\200umsg", h_umsg_command,   CM_HOST,
  836.     "\377\200user", h_user_command,   CM_HOST,
  837.  
  838.     0, 0, 0,
  839.   };
  840.   struct cmdtable *cmdp;
  841.  
  842.   sockowner(s,Curproc);    /* We own it now */
  843.  
  844.   cp = alloc_connection(s);
  845.  
  846.   for(pl = permlinks; pl; pl = pl->next)
  847.     if(pl->fd == s) {
  848.       pl->convection = cp;
  849.       if (pl->command != NULLCHAR) usprintf(s, "%s",pl->command);
  850.       cp->xmitted += usprintf(s, "/\377\200HOST %s\n", myhostname);
  851.     }
  852.  
  853.   if(pl == NULLPERMLINK) {
  854. #ifdef MAILBOX
  855.     getpeername(s,fsocket,&len);
  856.     ccp = strdup(psocket(fsocket));
  857.     if((cccp = strchr(ccp,':')) != NULLCHAR)
  858.       *cccp = '\0';
  859.     if(strcmp(ccp,inet_ntoa(Ip_addr)) != 0)
  860. #endif
  861.       usprintf(cp->fd,"\npse login with '/n <call>'\n\n");
  862.   }
  863.  
  864.   for (; ; ) {
  865. loop:
  866.     if(cp->type == CT_CLOSED)
  867.       break;
  868.     memset(cp->ibuf,0,sizeof(cp->ibuf));
  869.     if((size = recvline(cp->fd,cp->ibuf,sizeof(cp->ibuf))) <= 0)
  870.       break;
  871.     cp->received += size;
  872.     clear_locks(NULL,NULLCHAR,NULL);
  873.     cp->locked = 1;
  874.     if (*cp->ibuf == '/') {
  875.       ccp = &cp->ibuf[1];
  876.       arg[0] = '\0';
  877.       sscanf(ccp,"%s",arg);
  878.       arglen = strlen(arg);
  879.       for (cmdp = cmdtable; cmdp->name; cmdp++) {
  880.         if (!strncmp(cmdp->name, arg, arglen)) {
  881.           if (cmdp->states & (1 << cp->type))
  882.             (*cmdp->fnc)(cp);
  883.           goto loop;
  884.         }
  885.       }
  886.       if (cp->type == CT_USER) {
  887.                 time(&cxtime);
  888.         cp->xmitted += usprintf(cp->fd,
  889.           "%s *** Unknown command '/%s'. Type /help for Help.\n", cxxtime(ptime(&cxtime)), arg);
  890.            }
  891.       goto loop;
  892.     }
  893.     if((ccp = strpbrk(cp->ibuf,"\r\n")) != NULLCHAR)
  894.         *ccp = '\0';
  895.     if(isprint(cp->ibuf[0]) != 0 && cp->type == CT_USER)
  896.       send_msg_to_channel(cp->name, cp->channel, cp->ibuf);
  897.   }
  898.   bye_command(cp);
  899.   free_closed_connections(NULL,NULLCHAR,NULL);
  900.   return;
  901. }
  902.  
  903.  
  904. #endif /* CHATNODE */
  905.